package io.example.jdbc;

import io.example.model.ErrorCodes;
import io.vertx.core.AbstractVerticle;
import io.vertx.core.Future;
import io.vertx.core.eventbus.Message;
import io.vertx.core.json.JsonArray;
import io.vertx.core.json.JsonObject;
import io.vertx.ext.jdbc.JDBCClient;
import io.vertx.ext.sql.ResultSet;
import io.vertx.ext.sql.UpdateResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.List;

/**
 * Created by Administrator on 2018/3/9.
 * 数据库连接
 */
public class DemoDaoVerticle extends AbstractVerticle {
    private static final Logger logger = LoggerFactory.getLogger(DemoDaoVerticle.class);

    private JDBCClient dbClient;

    public void start(Future<Void> startFuture) throws Exception {
        //创建数据库客户端
        dbClient = JDBCClient.createShared(vertx, config());

        dbClient.getConnection(ar -> {
            if (ar.failed()) {
                logger.error("Could not open a database connection", ar.cause());
                startFuture.fail(ar.cause());
            } else {
                vertx.eventBus().consumer("demo.dao", this::onMessage);  // 注册事件监听
                startFuture.complete();
            }
        });
    }

    private void onMessage(Message<JsonObject> message) {
        if (!message.headers().contains("action")) {
            logger.error("No action header specified for message with headers {} and body {}",
                    message.headers(), message.body().encodePrettily());
            message.fail(ErrorCodes.NO_ACTION_SPECIFIED.ordinal(), "No action header specified");
            return;
        }
        String action = message.headers().get("action");

        switch (action) {
            case "selectAll":
                selectAll(message);
                break;
            case "delete":
                delete(message);
                break;
            case "save":
                save(message);
                break;
            default:
                message.fail(ErrorCodes.BAD_ACTION.ordinal(), "Bad action: " + action);
        }
    }

    private void selectAll(Message<JsonObject> message) {
        String sql = "select * from test";
        printSql(sql, null);
        dbClient.query(sql, res -> {
            if (res.succeeded()) {
                ResultSet resultSet = res.result();
                List<JsonObject> rows = resultSet.getRows();
                message.reply(new JsonObject().put("rows", rows));
            } else {
                reportQueryError(message, res.cause());
            }
        });
    }

    private void delete(Message<JsonObject> message) {
        JsonArray data = new JsonArray().add(message.body().getString("id"));
        String sql = "delete from test where id=?";
        printSql(sql, data);
        dbClient.updateWithParams(sql, data, res -> {
            if (res.succeeded()) {
                UpdateResult result = res.result();
                message.reply(new JsonObject().put("count", result.getUpdated()));
            } else {
                reportQueryError(message, res.cause());
            }
        });
    }

    private void save(Message<JsonObject> message) {
        JsonObject body = message.body();
        String sql;
        JsonArray params = new JsonArray();
        if (body.containsKey("id")) {
            sql = "update test set name = ? where id = ?";
            params.add(body.getString("name")).add(body.getValue("id"));
        } else {
            sql = "insert into test (name) values (?)";
            params.add(body.getString("name"));
        }
        printSql(sql, params);
        dbClient.updateWithParams(sql, params, res -> {
            if (res.succeeded()) {
                UpdateResult result = res.result();
                message.reply(new JsonObject().put("count", result.getUpdated()).put("primaryKey", result.getKeys()));
            } else {
                reportQueryError(message, res.cause());
            }
        });
    }

    private void reportQueryError(Message<JsonObject> message, Throwable cause) {
        logger.error("Database query error", cause);
        message.fail(ErrorCodes.DB_ERROR.ordinal(), cause.getMessage());
    }

    private void printSql(String sql, JsonArray params) {
        logger.debug("execute sql: {}", sql);
        if (params == null || params.isEmpty()) {
            return;
        }
        String paramsLog = "execute parameters:";
        for (Object obj : params) {
            paramsLog += obj.toString();
            paramsLog += ",";
        }
        logger.debug(paramsLog.substring(0, paramsLog.length() - 1));
    }
}
